package com.incar.chuxing.utils.ble.manager;

import com.incar.chuxing.utils.ble.bean.ControlResult;
import com.incar.chuxing.utils.ble.bean.OrderCmd;
import com.incar.chuxing.utils.ble.utils.AtomicIntegerUtil;
import com.incar.chuxing.utils.ble.utils.ConvertUtil;
import com.incar.chuxing.utils.ble.utils.HexUtil;
import com.incar.chuxing.utils.ble.utils.Logger;
import com.incar.chuxing.utils.ble.utils.PhoneUtils;

import java.util.concurrent.LinkedBlockingDeque;

/**
 * Created by xiongjida on 2017/6/19.
 */

/**
 * 管理BLE所有指令的获取
 */
public class DeviceControlManager {

    /**
     * 消息头
     */
    private static final byte[] header = new byte[]{0x7E, 0x10};

    private volatile static DeviceControlManager instance;

    private DeviceControlManager() {
    }

    public static DeviceControlManager getInstance() {
        if (instance == null) {
            synchronized (DeviceControlManager.class) {
                if (instance == null) {
                    instance = new DeviceControlManager();
                }
            }
        }
        return instance;
    }

    /**
     * 获取控制指令
     *
     * @param cmd                控制指令
     * @param controllCiphertext 加密密文
     */
    public OrderCmd getDeviceControlCmd(String cmd, String controllCiphertext,
                                        LinkedBlockingDeque<ControlResult> mControlCmds) {
        Logger.e("cmd:" + cmd);
        // 报文序列号,占用2字节
        byte[] serialNum = getSerialNum();
        // 命令标识,占用2个字节
        byte[] cmdIdentifier = new byte[]{0x0A, 0x01};
        // 控制密文,16字节
        byte[] controllCipherByte = HexUtil.hexStringToByteArray(controllCiphertext);
        // 控制指令
        byte[] controlCmd = ConvertUtil.stringToBytes(cmd);
        // 控制密文长度
        byte[] controlCmdLength = new byte[]{(byte) controlCmd.length};
        // 时间戳
        byte[] time = ConvertUtil.intToBytes(PhoneUtils.getCurrentTimeSecond(), true);
        // 内容
        byte[] content = ConvertUtil.byteMerger(serialNum, cmdIdentifier, controllCipherByte,
                controlCmdLength, controlCmd, time);
        // 指定指令
        byte[] controlBytes = ConvertUtil.crcEncrypt(content, header);
        mControlCmds.clear();
        // ControlResult controlResult = new
        // ControlResult(String.valueOf(System.currentTimeMillis()),
        // HexUtil.encodeHexStr(controlBytes));
        ControlResult controlResult = new ControlResult(String.valueOf(System.currentTimeMillis()),
                cmd);
        mControlCmds.offer(controlResult);
        return new OrderCmd(controlBytes, controlResult);

    }

    /**
     * 获取状态指令
     *
     * @return
     */
    public OrderCmd getDeviceStateCmd() {
        // 报文序列号,占用2字节
        byte[] serialNum = getSerialNum();
        // 命令标识,占用2个字节
        byte[] cmdIdentifier = new byte[]{0x0A, 0x06};
        // 时间戳
        byte[] time = ConvertUtil.intToBytes(PhoneUtils.getCurrentTimeSecond(), true);
        // 内容
        byte[] content = ConvertUtil.byteMerger(serialNum, cmdIdentifier, time);
        // 获取指令
        return new OrderCmd(ConvertUtil.crcEncrypt(content, header));
    }

    /**
     * 获取电量,里程等相关信息
     *
     * @return
     */
    public OrderCmd getDeviceCarInfo() {
        // 报文序列号,占用2字节
        byte[] serialNum = getSerialNum();
        // 命令标识,占用2个字节
        byte[] cmdIdentifier = new byte[]{0x02, (byte) 0x98};
        // 时间戳
        byte[] time = ConvertUtil.intToBytes(PhoneUtils.getCurrentTimeSecond(), true);
        // 内容
        byte[] content = ConvertUtil.byteMerger(serialNum, cmdIdentifier, time);
        // 获取指令
        return new OrderCmd(ConvertUtil.crcEncrypt(content, header));
    }

    /**
     * 获取gps指令
     *
     * @return
     */
    public OrderCmd getGPSDataCmd() {
        return new OrderCmd(getSimpleCmd(new byte[]{0x02, 0x43}));
    }

    /**
     * 获取唤醒指令
     *
     * @return
     */
    public byte[] getWakeUpCmd() {
        return getSimpleCmd(new byte[]{0x55, 0x55});
    }

    /**
     * 获取通用应答指令
     *
     * @return
     */
    public OrderCmd getNormalCmd(int obdSerialNum) {
        // 报文序列号,占用2字节
        byte[] serialNum = getSerialNum();
        // 命令标识,占用2个字节
        byte[] cmdIdentifier = new byte[]{0x60, 0x01};
        // 接收的报文流水号
        byte[] obdSerialByte = ConvertUtil.shortToBytes((short) obdSerialNum, true);
        // 结果
        byte[] result = new byte[]{0x00};
        // 内容
        byte[] content = ConvertUtil.byteMerger(serialNum, cmdIdentifier, obdSerialByte, result);
        // 获取指令
        return new OrderCmd(ConvertUtil.crcEncrypt(content, header));
    }

    /**
     * 获取仅和指令相关的命令内容
     *
     * @param cmd
     * @return
     */
    private byte[] getSimpleCmd(byte[] cmd) {
        // 报文序列号,占用2字节
        byte[] serialNum = getSerialNum();
        // 命令标识,占用2个字节
        byte[] cmdIdentifier = cmd;
        // 内容
        byte[] content = ConvertUtil.byteMerger(serialNum, cmdIdentifier);
        // 获取指令
        return ConvertUtil.crcEncrypt(content, header);
    }

    /**
     * 获取流水号（序列号）
     *
     * @return
     */
    private byte[] getSerialNum() {
        return AtomicIntegerUtil.getIncrementBytesID();
    }

}
